﻿using BaseFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace LiteFramework.Security
{
    /// <summary>
    /// DES : 对称加密。加密强度：AES > 3DES > DES。
    /// <para>　　密码为8byte长度。</para>
    /// </summary>
    public class DES : SecurityAbs
    {
        #region 成员变量
        /// <summary>
        /// 密钥(8位,不足在后面补0)
        /// </summary>
        private const string _defaultPassword = "m8*^)LT$";
        /// <summary>
        /// 运算模式
        /// </summary>
        private static CipherMode _cipherMode = CipherMode.ECB;
        /// <summary>
        /// 填充模式
        /// </summary>
        private static PaddingMode _paddingMode = PaddingMode.PKCS7;
        /// <summary>
        /// 字符串采用的编码
        /// </summary>
        private static Encoding _encoding = Encoding.UTF8;
        #endregion

        #region 辅助方法
        /// <summary>
        /// 获取8byte (64bit)的密钥数据
        /// </summary>
        /// <param name="password">密码</param>
        /// <returns></returns>
        private static byte[] GetKeyArray(string password)
        {
            int keyLen = 8;

            if (password == null)
            {
                password = string.Empty;
            }

            if (password.Length < keyLen)
            {
                password = password.PadRight(keyLen, '0');
            }
            else if (password.Length > keyLen)
            {
                password = password.Substring(0, keyLen);
            }


            byte[] source = EncodingHelper.GetBytes(password, _encoding);
            byte[] result = new byte[keyLen];
            Buffer.BlockCopy(source, 0, result, 0, keyLen);

            return result;
        }

        /// <summary>
        /// 将字符数组转换成字符串
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        private static string ConvertByteToString(byte[] inputData)
        {
            if (inputData == null)
                return null;

            StringBuilder sb = new StringBuilder(inputData.Length * 2);
            foreach (var b in inputData)
            {
                sb.Append(b.ToString("X2"));
            }
            return sb.ToString();
        }

        /// <summary>
        /// 将字符串转换成字符数组
        /// </summary>
        /// <param name="inputString"></param>
        /// <returns></returns>
        private static byte[] ConvertStringToByte(string inputString)
        {
            if (inputString == null)
                return null;

            if (inputString.Length < 2)
            {
                throw new ArgumentException();
            }

            int l = inputString.Length / 2;
            byte[] result = new byte[l];
            for (int i = 0; i < l; ++i)
            {
                result[i] = Convert.ToByte(inputString.Substring(2 * i, 2), 16);
            }

            return result;
        }
        #endregion

        /*
         * 加密时
         *  １.对于传入的字符串，通过EncodingHelper.GetBytes()方法，转换成字节流；
         *  ２.对字节流执行加密方法，并返回加密后的结果字节流；
         *  ３.再通过ConvertByteToString()方法，把返回的结果字节流，转换成16进制字符串
         * 
         * 解密时
         *  １.对于传入的字符串，通过ConvertStringToByte()方法，转换成字节流；
         *  ２.对字节流执行解密方法，并返回解密后的结果字节流；
         *  ３.再通过EncodingHelper.GetString()方法，把返回的结果字节流，转换成字符串原文
        */

        #region 加密

        /// <summary>
        /// 使用默认密码加密字符串(加密返回16进制字符串)
        /// </summary>
        /// <param name="inputString">需要加密的字符串</param>
        /// <returns>返回加密后的字符串（16进制字符串）</returns>
        public static string Encrypt(string inputString)
        {
            byte[] inputData = EncodingHelper.GetBytes(inputString, _encoding);
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(_defaultPassword));
            string encryptString = ConvertByteToString(encryptBytes);
            return encryptString;
        }
        /// <summary>
        /// 使用默认密码加密字节数组(加密返回16进制字符串)
        /// </summary>
        /// <param name="inputData">需要加密的字节数组</param>
        /// <returns>返回加密后的字符串（16进制字符串）</returns>
        public static string Encrypt(byte[] inputData)
        {
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(_defaultPassword));
            string encryptString = ConvertByteToString(encryptBytes);
            return encryptString;
        }

        /// <summary>
        /// 使用默认密码加密字符串
        /// </summary>
        /// <param name="inputString">需要加密的字符串</param>
        /// <returns>返回加密后的字节数组</returns>
        public static byte[] EncryptExt(string inputString)
        {
            byte[] inputData = EncodingHelper.GetBytes(inputString, _encoding);
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(_defaultPassword));
            return encryptBytes;
        }
        /// <summary>
        /// 使用默认密码加密字节数组
        /// </summary>
        /// <param name="inputData">需要加密的字节数组</param>
        /// <returns>返回加密后的字节数组</returns>
        public static byte[] EncryptExt(byte[] inputData)
        {
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(_defaultPassword));
            return encryptBytes;
        }


        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="inputString">需要加密的字符串</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回加密后的字符串（16进制字符串）</returns>
        public static string Encrypt(string inputString, string password)
        {
            byte[] inputData = EncodingHelper.GetBytes(inputString, _encoding);
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(password));
            string encryptString = ConvertByteToString(encryptBytes);
            return encryptString;
        }
        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="inputString">需要加密的字符串</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回加密后的字符串（16进制字符串）</returns>
        public static string Encrypt(string inputString, byte[] password)
        {
            byte[] inputData = EncodingHelper.GetBytes(inputString, _encoding);
            byte[] encryptBytes = __fef68072_encrypt(inputData, password);
            string encryptString = ConvertByteToString(encryptBytes);
            return encryptString;
        }
        /// <summary>
        /// 加密字节数组
        /// </summary>
        /// <param name="inputData">需要加密的字节数组</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回加密后的字符串（16进制字符串）</returns>
        public static string Encrypt(byte[] inputData, string password)
        {
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(password));
            string encryptString = ConvertByteToString(encryptBytes);
            return encryptString;
        }
        /// <summary>
        /// 加密字节数组
        /// </summary>
        /// <param name="inputData">需要加密的字节数组</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回加密后的字符串（16进制字符串）</returns>
        public static string Encrypt(byte[] inputData, byte[] password)
        {
            byte[] encryptBytes = __fef68072_encrypt(inputData, password);
            string encryptString = ConvertByteToString(encryptBytes);
            return encryptString;
        }

        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="inputString">需要加密的字符串</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回加密后的字节数组</returns>
        public static byte[] EncryptExt(string inputString, string password)
        {
            byte[] inputData = EncodingHelper.GetBytes(inputString, _encoding);
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(password));
            return encryptBytes;
        }
        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="inputString">需要加密的字符串</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回加密后的字节数组</returns>
        public static byte[] EncryptExt(string inputString, byte[] password)
        {
            byte[] inputData = EncodingHelper.GetBytes(inputString, _encoding);
            byte[] encryptBytes = __fef68072_encrypt(inputData, password);
            return encryptBytes;
        }
        /// <summary>
        /// 加密字节数组
        /// </summary>
        /// <param name="inputData">需要加密的字节数组</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回加密后的字节数组</returns>
        public static byte[] EncryptExt(byte[] inputData, string password)
        {
            byte[] encryptBytes = __fef68072_encrypt(inputData, GetKeyArray(password));
            return encryptBytes;
        }
        /// <summary>
        /// 加密字节数组
        /// </summary>
        /// <param name="inputData">需要加密的字节数组</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回加密后的字节数组</returns>
        public static byte[] EncryptExt(byte[] inputData, byte[] password)
        {
            byte[] encryptBytes = __fef68072_encrypt(inputData, password);
            return encryptBytes;
        }


        /// <summary>
        /// 加密字节数组
        /// </summary>
        /// <param name="inputData">需要加密的字节数组</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回加密后的字节数组</returns>
        public static byte[] __fef68072_encrypt(byte[] inputData, byte[] password)
        {
            if (inputData == null)
                return null;

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            des.Key = password;
            des.Mode = _cipherMode;
            des.Padding = _paddingMode;
            ICryptoTransform transform = des.CreateEncryptor();
            byte[] data = null;
            try
            {
                data = transform.TransformFinalBlock(inputData, 0, inputData.Length);
            }
            catch
            {
                throw;
            }
            finally
            {
                des.Clear();
            }

            return data;
        }

        #endregion

        #region 解密

        /// <summary>
        /// 使用默认密码解密字符串（解密16进制字符串）
        /// </summary>
        /// <param name="inputString">需要解密的字符串（16进制字符串）</param>
        /// <returns>返回解密后的字符串</returns>
        public static string Decrypt(string inputString)
        {
            byte[] inputData = ConvertStringToByte(inputString);
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(_defaultPassword));
            string decryptString = EncodingHelper.GetString(decryptBytes, _encoding);
            return decryptString;
        }
        /// <summary>
        /// 使用默认密码解密字节数组
        /// </summary>
        /// <param name="inputData">需要解密的字节数组</param>
        /// <returns>返回解密后的字符串</returns>
        public static string Decrypt(byte[] inputData)
        {
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(_defaultPassword));
            string decryptString = EncodingHelper.GetString(decryptBytes, _encoding);
            return decryptString;
        }

        /// <summary>
        /// 使用默认密码解密字符串（解密16进制字符串）
        /// </summary>
        /// <param name="inputString">需要解密的字符串（16进制字符串）</param>
        /// <returns>返回解密后的字节数组</returns>
        public static byte[] DecryptExt(string inputString)
        {
            byte[] inputData = ConvertStringToByte(inputString);
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(_defaultPassword));
            return decryptBytes;
        }
        /// <summary>
        /// 使用默认密码解密字节数组
        /// </summary>
        /// <param name="inputData">需要解密的字节数组</param>
        /// <returns>返回解密后的字节数组</returns>
        public static byte[] DecryptExt(byte[] inputData)
        {
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(_defaultPassword));
            return decryptBytes;
        }



        /// <summary>
        /// 解密字符串（解密16进制字符串）
        /// </summary>
        /// <param name="inputString">需要解密的字符串（16进制字符串）</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回解密后的字符串</returns>
        public static string Decrypt(string inputString, string password)
        {
            byte[] inputData = ConvertStringToByte(inputString);
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(password));
            string decryptString = EncodingHelper.GetString(decryptBytes, _encoding);
            return decryptString;
        }
        /// <summary>
        /// 使用默认密码解密字符串（解密16进制字符串）
        /// </summary>
        /// <param name="inputString">需要解密的字符串（16进制字符串）</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回解密后的字符串</returns>
        public static string Decrypt(string inputString, byte[] password)
        {
            byte[] inputData = ConvertStringToByte(inputString);
            byte[] decryptBytes = __fef68072_decrypt(inputData, password);
            string decryptString = EncodingHelper.GetString(decryptBytes, _encoding);
            return decryptString;
        }
        /// <summary>
        /// 使用默认密码解密字节数组
        /// </summary>
        /// <param name="inputData">需要解密的字节数组</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回解密后的字符串</returns>
        public static string Decrypt(byte[] inputData, string password)
        {
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(password));
            string decryptString = EncodingHelper.GetString(decryptBytes, _encoding);
            return decryptString;
        }
        /// <summary>
        /// 解密字节数组
        /// </summary>
        /// <param name="inputData">要解密的字节数组</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回解密后的字符串</returns>
        public static string Decrypt(byte[] inputData, byte[] password)
        {
            byte[] decryptBytes = __fef68072_decrypt(inputData, password);
            string decryptString = EncodingHelper.GetString(decryptBytes, _encoding);
            return decryptString;
        }


        /// <summary>
        /// 使用默认密码解密字符串（解密16进制字符串）
        /// </summary>
        /// <param name="inputString">需要解密的字符串（16进制字符串）</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回解密后的字节数组</returns>
        public static byte[] DecryptExt(string inputString, string password)
        {
            byte[] inputData = ConvertStringToByte(inputString);
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(password));
            return decryptBytes;
        }
        /// <summary>
        /// 使用默认密码解密字符串（解密16进制字符串）
        /// </summary>
        /// <param name="inputString">需要解密的字符串（16进制字符串）</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回解密后的字节数组</returns>
        public static byte[] DecryptExt(string inputString, byte[] password)
        {
            byte[] inputData = ConvertStringToByte(inputString);
            byte[] decryptBytes = __fef68072_decrypt(inputData, password);
            return decryptBytes;
        }
        /// <summary>
        /// 解密字节数组
        /// </summary>
        /// <param name="inputData">要解密的字节数组</param>
        /// <param name="password">密码（最长8字节）</param>
        /// <returns>返回解密后的字节数组</returns>
        public static byte[] DecryptExt(byte[] inputData, string password)
        {
            byte[] decryptBytes = __fef68072_decrypt(inputData, GetKeyArray(password));
            return decryptBytes;
        }
        /// <summary>
        /// 解密字节数组
        /// </summary>
        /// <param name="inputData">要解密的字节数组</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回解密后的字节数组</returns>
        public static byte[] DecryptExt(byte[] inputData, byte[] password)
        {
            byte[] decryptBytes = __fef68072_decrypt(inputData, password);
            return decryptBytes;
        }


        /// <summary>
        /// 解密字节数组
        /// </summary>
        /// <param name="inputData">要解密的字节数组</param>
        /// <param name="password">密码（固定8字节）</param>
        /// <returns>返回解密后的字节数组</returns>
        private static byte[] __fef68072_decrypt(byte[] inputData, byte[] password)
        {
            if (inputData == null)
                return null;

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            des.Key = password;
            des.Mode = _cipherMode;
            des.Padding = _paddingMode;
            ICryptoTransform transform = des.CreateDecryptor();
            byte[] data = null;
            try
            {
                data = transform.TransformFinalBlock(inputData, 0, inputData.Length);
            }
            catch
            {
                throw;
            }
            finally
            {
                des.Clear();
            }

            return data;
        }

        #endregion
    }
}
